package raft

//
// this is an outline of the API that raftss must expose to
// the service (or tester). see comments below for
// each of these functions for more details.
//
// rf = Make(...)
//   create a new Raft server.
// rf.Start(command interface{}) (index, term, isleader)
//   start agreement on a new log entry
// rf.GetState() (term, isLeader)
//   ask a Raft for its current term, and whether it thinks it is leader
// ApplyMsg
//   each time a new entry is committed to the log, each Raft peer
//   should send an ApplyMsg to the service (or tester)
//   in the same server.
//

import (
	"math/rand"
	"sync"
	"time"
)
import "demo/labrpc"

// import "bytes"
// import "encoding/gob"



//
// as each Raft peer becomes aware that successive log entries are
// committed, the peer should send an ApplyMsg to the service (or
// tester) on the same server, via the applyCh passed to Make().
//
type ApplyMsg struct {
	Index       int
	Command     interface{}
	UseSnapshot bool   // ignore for lab2; only used in lab3
	Snapshot    []byte // ignore for lab2; only used in lab3
}

//
// A Go object implementing a single Raft peer.
//
type Raft struct {
	mu        sync.Mutex          // Lock to protect shared access to this peer's state
	peers     []*labrpc.ClientEnd // RPC end points of all peers
	persister *Persister          // Object to hold this peer's persisted state
	me        int                 // this peer's index into peers[]


	//判断当前结点是否是Leader
	isLeader bool
	resetTimer chan struct{} //充值选举超时
	electionTime *time.Timer //选举超时实例
	electionTimeout time.Duration
	hearBEATInterval time.Duration
	// Your data here (2A, 2B, 2C).
	// Look at the paper's Figure 2 for a description of what
	// state a Raft server must maintain.

	//Server 存储的最新任期
     CurrentTerm int
	//投票给那个Server
	VotedFor int
	//日志
	Los []LogEntry
	comm *sync.Cond //保持提交索引一致
	newEntryCond []*sync.Cond //保持一致性
	//当前被提交的索引值
	commitIndex int
	//被执行的日志条目的索引值
	lastApplied int
	//需要发送给下一个服务器的索引值
	nextIndex []int
	matchIndex []int //对于每一个服务器,已经复制给他的最高索引
	applyCh chan ApplyMsg //日志提交成功,向服务发起应用消息
	shutdown chan struct{} //中断标志
}

// return currentTerm and whether this server
// believes it is the leader.
func (rf *Raft) GetState() (int, bool) {

	var term int
	var isleader bool
	// Your code here (2A).
	rf.mu.Lock()
	term = rf.CurrentTerm
	isleader = rf.isLeader
	defer rf.mu.Unlock()
	return term, isleader
}





//
// the service using Raft (e.g. a k/v server) wants to start
// agreement on the next command to be appended to Raft's log. if this
// server isn't the leader, returns false. otherwise start the
// agreement and return immediately. there is no guarantee that this
// command will ever be committed to the Raft log, since the leader
// may fail or lose an election.
//
// the first return value is the index that the command will appear at
// if it's ever committed. the second return value is the current
// term. the third return value is true if this server believes it is
// the leader.
//
func (rf *Raft) Start(command interface{}) (int, int, bool) {
	index := -1
	term := -1
	isLeader := true

	// Your code here (2B).


	return index, term, isLeader
}

//
// the tester calls Kill() when a Raft instance won't
// be needed again. you are not required to do anything
// in Kill(), but it might be convenient to (for example)
// turn off debug output from this instance.
//
func (rf *Raft) Kill() {
	// Your code here, if desired.
}

//
// the service or tester wants to create a Raft server. the ports
// of all the Raft servers (including this one) are in peers[]. this
// server's port is peers[me]. all the servers' peers[] arrays
// have the same order. persister is a place for this server to
// save its persistent state, and also initially holds the most
// recent saved state, if any. applyCh is a channel on which the
// tester or service expects Raft to send ApplyMsg messages.
// Make() must return quickly, so it should start goroutines
// for any long-running work.
// 创建Raft节点服务
func Make(peers []*labrpc.ClientEnd, me int,
	persister *Persister, applyCh chan ApplyMsg) *Raft {
	rf := &Raft{}
	rf.peers = peers
	rf.persister = persister
	rf.me = me
	rf.applyCh = applyCh

	// Your initialization code here (2A, 2B, 2C).
    //所有结点初始状态都是follower
    rf.isLeader = false
    rf.VotedFor = -1

    rf.nextIndex = make([]int,len(peers))
    rf.matchIndex = make([]int,len(peers))
    rf.Los = make([]LogEntry,1)
    rf.Los[0] = LogEntry{
		Term:    0,
		Command: nil,
	}
	rf.shutdown = make(chan struct{})

	for i := 0 ; i < len(peers); i++  {
		//初始值是leader最新一条日志的索引+1
		rf.nextIndex[i] = len(rf.Los)
	}
    //初始化重置超时选举
    rf.resetTimer = make(chan struct{})
    rf.comm = sync.NewCond(&rf.mu)
    rf.newEntryCond = make([]*sync.Cond,len(peers))
	for i:= 0;i < len(peers) ; i++  {
		rf.newEntryCond[i] = sync.NewCond(&rf.mu)
	}
    //设置选举超时时间 150-300ms 为了防止选举出2个leader
    rf.electionTimeout = time.Millisecond*(150 + time.Duration(rand.Int63()%400))
	rf.electionTime = time.NewTimer(rf.electionTimeout)
     //设置心跳超时时间
     rf.hearBEATInterval = time.Millisecond * 200
     go rf.electionDaemo()
    // initialize from state persisted before a crash
	rf.readPersist(persister.ReadRaftState())
	return rf
}
